package com.neusoft.thread10forkjoin;

import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * 并行计算的框架Fork/Join，可以解决我们系统中大数据计算的性能问题。
 * Fork/Join采用的是分治法，Fork是将一个大任务拆分成若干个子任务，子任务分别去计算，
 * 而Join是获取到子任务的计算结果，然后合并，这个是递归的过程。子任务被分配到不同的核上执行时，效率最高。
 * @author Zhang.Yan
 *
 */
public class ForkJoinTest extends RecursiveTask<Integer>
{

	
    private static final int THRESHOLD = 500000;

	private long[] array;

	private int low;

	private int high;

	private static final long serialVersionUID = 5472215578397557468L;


	public ForkJoinTest(long[] array,int low ,int high)
	{
		this.array=array;
		this.low=low;
		this.high=high;
	}
	
	@Override
	protected Integer compute()
	{
		int sum=0;
		if(high-low<THRESHOLD)
		{
			 // 小于阈值则直接计算
			for(int i=low;i<high;i++)
			{
				sum+=array[i];
			}
		}
		else
		{
			// 1.一个大任务分割成两个子任务
			int mid=(high+low)>>>1;
			ForkJoinTest left=new ForkJoinTest(array, low, mid);
			ForkJoinTest right=new ForkJoinTest(array, mid, high);
			// 2. 分别计算
			left.fork();
            right.fork();
            // 3. 合并结果
            sum = left.join() + right.join();
		}
		return sum;
	}
	

	
	public static void main(String[] args) throws InterruptedException, ExecutionException 
	{
		long begin = System.currentTimeMillis();
		long[] array = genArray(1000000);
        System.out.println(Arrays.toString(array));
        // 1. 创建任务
        ForkJoinTest sumTask = new ForkJoinTest(array, 0, array.length - 1);
        // 2. 创建线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        // 3. 提交任务到线程池
        forkJoinPool.submit(sumTask);
        // 4. 获取结果
        Integer result = sumTask.get();
        long end = System.currentTimeMillis();
	   System.out.println(String.format("结果 %s 耗时 %sms",result,end-begin));
	}
	
	 private static long[] genArray(int size) 
	 {
       long[] array = new long[size];
       for (int i = 0; i < size; i++) 
       {
           array[i] = new Random().nextLong();
       }
       return array;
	 }



}
